package midend;

import midend.IR_Value.IR_BaseBlock;
import midend.IR_Value.IR_FuncBlock;
import midend.IR_Instruction.*;
import midend.IR_Value.IR_Value;
import midend.IR_Value.IR_Int_Value;

import java.util.List;
import java.util.Set;
import java.util.Map;

public class Iterator_Analysis {

    /**
     * 对函数进行迭代器分析
     * 
     * @param funcBlock 函数块
     */
    public static void iteratorAnalysis(IR_FuncBlock funcBlock) {
        Set<Loop> loops = funcBlock.getLoops();
        if (loops == null) {
            return;
        }

        for (Loop loop : loops) {
            analyzeLoop(loop);
        }
    }

    /**
     * 分析单个循环的迭代信息
     * 
     * @param loop 循环对象
     */
    private static void analyzeLoop(Loop loop) {
        IR_BaseBlock header = loop.getHeader();
        List<Instruction> instrList = header.get_Instruction_List();

        // 获取循环头的最后一条指令（分支指令）
        if (instrList.isEmpty()) {
            return;
        }

        Instruction lastInstr = instrList.get(instrList.size() - 1);
        if (!(lastInstr instanceof Branch_Instruction)) {
            return;
            //loop header的最后一条指令一定是分支指令
            //throw new RuntimeException("loop header的最后一条指令一定是分支指令");
        }

        Branch_Instruction brInstr = (Branch_Instruction) lastInstr;
        analyzeBranchInstruction(loop, brInstr);
    }

    /**
     * 分析分支指令
     * 
     * @param loop    循环对象
     * @param brInstr 分支指令
     */
    private static void analyzeBranchInstruction(Loop loop, Branch_Instruction brInstr) {
        IR_Value itBegin = null, itCmp = null, itVar = null, itEnd = null;
        IR_Value itAlu = null, itChange = null;
        String op = null;
        boolean isUseLess = false;

        // 检查是否为无条件分支
        if (!brInstr.br_type()) {
            // 无条件分支，如 while(1)
            loop.setLoopIterator(itBegin, itCmp, itVar, itEnd, op, itAlu, itChange, true);
            return;
        }

        // 获取分支条件
        IR_Value brValue = brInstr.get_op().get(0);

        // 检查常量条件
        if (brValue instanceof IR_Int_Value) {
            IR_Int_Value constValue = (IR_Int_Value) brValue;
            if (constValue.get_Int_Value() == 0) {
                // while(0) - 永不执行的循环
                loop.setLoopIterator(itBegin, itCmp, itVar, itEnd, op, itAlu, itChange, true);
                return;
            } else if (constValue.get_Int_Value() == 1) {
                // while(1) - 无限循环
                itBegin = new IR_Int_Value(1, constValue.get_Type(), true);
                itEnd = new IR_Int_Value(1, constValue.get_Type(), true);
                itChange = new IR_Int_Value(0, constValue.get_Type(), true);
                loop.setLoopIterator(itBegin, itCmp, itVar, itEnd, "add", itAlu, itChange, false);
                return;
            }
        }

        // 检查是否为比较指令的结果
        // 需要找到产生这个值的指令
        Instruction defInstr = findDefiningInstruction(brValue, loop.getHeader());
        if (defInstr == null || !(defInstr instanceof Cond_Instruction)) {
            // 非比较分支，跳过
            return;
        }

        Cond_Instruction cmpInstr = (Cond_Instruction) defInstr;
        itCmp = brValue; // 使用比较指令的结果值

        // 识别迭代变量
        IR_Value left = cmpInstr.get_op().get(1);
        IR_Value right = cmpInstr.get_op().get(2);

        // 检查是否有Phi指令作为操作数
        Instruction leftDef = findDefiningInstruction(left, loop.getHeader());
        Instruction rightDef = findDefiningInstruction(right, loop.getHeader());

        if (leftDef instanceof Phi_Instruction) {
            itVar = left;
            itEnd = right;
        } else if (rightDef instanceof Phi_Instruction) {
            itVar = right;
            itEnd = left;
        } else {
            // 没有Phi指令，无法识别迭代变量
            return;
        }

        // 分析迭代变量
        analyzeIteratorVariable(loop, itVar, itBegin, itCmp, itEnd, itAlu, itChange, op);
    }

    /**
     * 查找定义某个值的指令
     * 
     * @param value 要查找的值
     * @param block 基本块
     * @return 定义该值的指令，如果没找到则返回null
     */
    private static Instruction findDefiningInstruction(IR_Value value, IR_BaseBlock block) {
        for (Instruction instr : block.get_Instruction_List()) {
            if (instr.get_op().size() > 0 && instr.get_op().get(0).equals(value)) {
                return instr;
            }
        }
        return null;
    }

    /**
     * 分析迭代变量
     * 
     * @param loop     循环对象
     * @param itVar    迭代变量
     * @param itBegin  起始值
     * @param itCmp    比较指令
     * @param itEnd    结束值
     * @param itAlu    计算指令
     * @param itChange 步长值
     * @param op       操作符
     */
    private static void analyzeIteratorVariable(Loop loop, IR_Value itVar,
            IR_Value itBegin, IR_Value itCmp,
            IR_Value itEnd, IR_Value itAlu,
            IR_Value itChange, String op) {
        
        // 找到定义itVar的Phi指令
        Instruction defInstr = findDefiningInstruction(itVar, loop.getHeader());
        if (defInstr == null || !(defInstr instanceof Phi_Instruction)) {
            return;
        }

        Phi_Instruction phiInstr = (Phi_Instruction) defInstr;

        // 找到循环的latch块
        IR_BaseBlock latchBlock = getLoopLatch(loop);
        if (latchBlock == null) {
            return;
        }

        // 确定起始值
        // 找到latch块对应的值
        IR_Value latchValue = phiInstr.get_ComingValues().get(latchBlock);
        if (latchValue == null) {
            return;
        }
        
        // 找到非latch块的值作为起始值
        for (Map.Entry<IR_BaseBlock, IR_Value> entry : phiInstr.get_ComingValues().entrySet()) {
            if (!entry.getKey().equals(latchBlock)) {
                itBegin = entry.getValue();
                break;
            }
        }
        
        if (itBegin == null) {
            return;
        }

        // 获取迭代更新指令
        IR_Value updateValue = phiInstr.get_ComingValues().get(latchBlock);
        if (updateValue == null) {
            return;
        }

        // 找到更新指令
        Instruction updateInstr = findDefiningInstruction(updateValue, latchBlock);
        if (updateInstr == null || !(updateInstr instanceof Calc_Instruction)) {
            return;
        }

        Calc_Instruction aluInstr = (Calc_Instruction) updateInstr;
        itAlu = updateValue;
        op = aluInstr.get_op_Type();

        // 提取步长值
        IR_Value left = aluInstr.get_op().get(1);
        IR_Value right = aluInstr.get_op().get(2);

        if (left.equals(itVar)) {
            itChange = right;
        } else if (right.equals(itVar)) {
            itChange = left;
        } else {
            return;
        }

        // 验证操作符支持
        if (op.equals("add") || op.equals("sub") || op.equals("mul")) {
            loop.setLoopIterator(itBegin, itCmp, itVar, itEnd, op, itAlu, itChange, false);
        }
//        else{
//            //throw new RuntimeException("不支持的操作符");
//            return;
//        }
    }

    /**
     * 获取循环的latch块
     * 
     * @param loop 循环对象
     * @return latch块，如果不存在则返回null
     */
    private static IR_BaseBlock getLoopLatch(Loop loop) {
        IR_BaseBlock head = loop.getHeader();
        IR_BaseBlock latch = null;

        for (IR_BaseBlock pred : head.getPreBlock()) {
            if (loop.isInLoop(pred)) {
                if (latch != null) {
                    return null; // 多个latch，无法确定
                }
                latch = pred;
            }
        }

        return latch;
    }
}
